﻿using Hx.ADSyncPlatform.ActiveDirectory.Access;
using Hx.ADSyncPlatform.ActiveDirectory.Extension;
using Hx.ADSyncPlatform.ActiveDirectory.Model;
using Hx.ADSyncPlatform.ActiveDirectory.Service.Base;
using Hx.ADSyncPlatform.Entity.Entities;
using Hx.ADSyncPlatform.Infrastructure.Page;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.Linq;

namespace Hx.ADSyncPlatform.ActiveDirectory.Service
{
    /// <summary>
    /// 人员
    /// </summary>
    public class PersonService : BaseService
    {

        private ADConnection ADCInfo;
        public PersonService(ADConnection _adcInfo)
        {
            this.ADCInfo = _adcInfo;
        }

        /// <summary>
        /// 单个人员
        /// </summary>
        /// <param name="sAMAccountName">账户名</param>
        /// <param name="searchLocation">查找位置</param>
        /// <returns>单个人员信息</returns>
        public Person Single(string sAMAccountName)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var person = new PersonAccess().Single(adc.RootEntry, sAMAccountName);
                return person == null ? null : person.Properties?.ConvertTo<Person>();
            }
        }


        public Person SearchInRoot(string sAMAccountName)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var de = new DirectoryEntry(adc.RootPath, adc.UserName, adc.Password);
                var person = new PersonAccess().Single(de, sAMAccountName);
                return person == null ? null : person.Properties?.ConvertTo<Person>();
            }
        }
        ///// <summary>
        ///// 单个人员
        ///// </summary>
        ///// <param name="sAMAccountName">账户名</param>
        ///// <param name="searchLocation">查找位置</param>
        ///// <returns>单个人员信息</returns>
        //public Person SingleByGuid(string guid)
        //{
        //    using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
        //    {
        //        var person = new PersonAccess().Single(adc.RootEntry, sAMAccountName);
        //        return person == null ? null : person.Properties?.ConvertTo<Person>();
        //    }
        //}

        /// <summary>
        /// 人员列表
        /// 根据显示名进行模糊查询
        /// </summary>
        /// <param name="displayName">显示名称</param>
        /// <param name="searchLocation">查找位置</param>
        /// <returns>人员集合</returns>
        public List<Person> List(string displayName)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var persons = new PersonAccess().Get(adc.RootEntry, displayName);
                List<Person> data = new List<Person>();

                if (persons == null || persons.Count == 0)
                {
                    return data;
                }

                foreach (SearchResult person in persons)
                {
                    var item = person?.Properties?.ConvertTo<Person>();
                    if (item != null)
                    {
                        data.Add(item);
                    }
                }
                return data;
            }
        }

        /// <summary>
        /// 查询人员
        /// 某组织下人员
        /// </summary>
        /// <param name="orgCn">组织CN</param>
        /// <param name="searchScope">查找层级</param>
        /// <param name="searchLocation">查找位置</param>
        /// <returns>人员集合</returns>
        public List<Person> List(string distinguishedName, string displayName, List<Plat_DataPermission> dataPermissions, List<string> systemOus, string searchScope = "current")
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                SearchResultCollection src = null;

                if (!string.IsNullOrEmpty(distinguishedName))
                {
                    DirectoryEntry org = null;
                    var orgDe = new OrganizationAccess().SingleByDistinguishedName(adc.RootEntry, distinguishedName);
                    if (orgDe == null)
                    {
                        throw new ActiveDirectoryObjectNotFoundException($"组织【{distinguishedName}】不存在，查询无法继续。");
                    }
                    org = orgDe.GetDirectoryEntry();
                    if (searchScope == "current")
                    {
                        src = new PersonAccess().Get(org, SearchScope.OneLevel, displayName);
                    }
                    else if (searchScope == "global")
                    {
                        src = new PersonAccess().Get(adc.RootEntry, SearchScope.Subtree, displayName);
                    }

                }
                else
                {
                    if (!string.IsNullOrEmpty(displayName))
                    {
                        src = new PersonAccess().Get(adc.RootEntry, displayName);
                    }
                    else
                    {
                        src = new PersonAccess().Get(adc.RootEntry, SearchScope.OneLevel);
                    }

                }
                var searchResults = src.OfType<SearchResult>();
                if (base.filterObjectByDataPermission != null)
                {
                    searchResults = filterObjectByDataPermission(searchResults, dataPermissions, systemOus);
                }
                List<Person> data = new List<Person>();
                if (src == null || src.Count == 0)
                {
                    return data;
                }
                foreach (SearchResult person in searchResults)
                {
                    var personItem = person.Properties?.ConvertTo<Person>();
                    if (personItem != null)
                    {
                        data.Add(personItem);
                    }
                }
                return data;



            }
        }

        /// <summary>
        /// 根据用户账号，查询用户信息
        /// </summary>
        /// <param name="samAccountNames">需要查询的用户账户</param>
        /// <param name="propertiesToLoad">需要返回的参数</param>
        /// <param name="searchLocation">查找位置</param>
        /// <returns>返回用户SearchResultCollection</returns>
        public List<Person> List(List<string> samAccountNames, List<string> propertiesToLoad)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var persons = new PersonAccess().Get(adc.RootEntry, samAccountNames.ToList(), propertiesToLoad.ToList());
                List<Person> data = new List<Person>();
                if (persons == null || persons.Count == 0)
                {
                    return data;
                }

                foreach (SearchResult person in persons)
                {
                    var item = person?.Properties?.ConvertTo<Person>(propertiesToLoad);
                    if (item != null)
                    {
                        data.Add(item);
                    }
                }
                return data;
            }
        }



        /// <summary>
        /// 查询人员分页
        /// </summary>
        /// <param name="orgCn">组织CN</param>
        /// <param name="displayName">显示名</param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns>人员分页集合</returns>
        public PageResult<Person> PageList(string distinguishedName, string displayName, List<Plat_DataPermission> dataPermissions, List<string> systemOus, string searchScope = "current", int pageIndex = 1, int pageSize = 10)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                SearchResultCollection src = null;

                DirectoryEntry org = null;


                if (searchScope == "current")
                {
                    var orgDe = new OrganizationAccess().SingleByDistinguishedName(adc.RootEntry, distinguishedName);
                    if (orgDe == null)
                    {
                        //throw new ActiveDirectoryObjectNotFoundException($"组织【{distinguishedName}】不存在，查询无法继续。");
                        return PageResult<Person>.Default();
                    }
                    org = orgDe.GetDirectoryEntry();
                    src = new PersonAccess().Get(org, SearchScope.OneLevel, displayName);
                }
                else if (searchScope == "global")
                {
                    src = new PersonAccess().Get(adc.RootEntry, SearchScope.Subtree, displayName);
                }
                var searchResults = src.OfType<SearchResult>();
                if (base.filterObjectByDataPermission != null)
                {
                    searchResults = filterObjectByDataPermission(searchResults, dataPermissions, systemOus);
                }
                int total = searchResults.Count();
                int startNum = Math.Max(pageIndex - 1, 0) * pageSize;
                searchResults = searchResults.Skip(startNum).Take(pageSize);


                var personList = searchResults.Select(n =>
                {
                    return n.Properties?.ConvertTo<Person>();

                }).ToList();
                PageResult<Person> pageResult = new PageResult<Person>(personList, pageIndex, total);
                return pageResult;



            }
        }
        public PageResult<Person> SearchPersonPage(string displayName, int pageIndex = 1, int pageSize = 10)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                SearchResultCollection src = null;
                src = new PersonAccess().Get(adc.RootEntry, SearchScope.Subtree, displayName);

                int total = src.Count;
                int startNum = Math.Max(pageIndex - 1, 0) * pageSize;
                var searchResults = src.OfType<SearchResult>().Skip(startNum).Take(pageSize);

                var personList = searchResults.Select(n =>
                {
                    return n.Properties?.ConvertTo<Person>();

                }).ToList();

                PageResult<Person> pageResult = new PageResult<Person>(personList, pageIndex, total);
                return pageResult;



            }
        }



        /// <summary>
        /// 自定义查询人员 分页
        /// </summary>
        /// <param name="filter">LDAP语句</param>
        /// <param name="propertiesToLoad">返回的属性</param>
        /// <param name="searchScope">查询层级</param>
        /// <param name="pagination">分页信息</param>
        /// <returns>人员列表以及分页信息</returns>
        public PageResult<Person> SearchPageList(string filter, List<string> propertiesToLoad, SearchScopeDerivation searchScope, Pagination pagination)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {

                var src = new PersonAccess().Search(adc.RootEntry, filter, propertiesToLoad, searchScope.Convert());
                int total = src.Count;
                int startNum = Math.Max(pagination.pageNum - 1, 0) * pagination.pageSize;
                var searchResults = src.OfType<SearchResult>().Skip(startNum).Take(pagination.pageSize);

                var personList = searchResults.Select(n =>
                {
                    return n.Properties?.ConvertTo<Person>();

                }).ToList();

                PageResult<Person> pageResult = new PageResult<Person>(personList, pagination.pageNum, total);
                return pageResult;

            }
        }


        /// <summary>
        /// 自定义查询人员 全量
        /// </summary>
        /// <param name="filter">LDAP语句</param>
        /// <param name="propertiesToLoad">返回的属性</param>
        /// <param name="searchScope">查询层级</param>
        /// <param name="pagination">分页信息</param>
        /// <returns>人员列表以及分页信息</returns>
        public List<Person> SearchList(string filter, List<string> propertiesToLoad, SearchScopeDerivation searchScope, Pagination pagination)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var src = new PersonAccess().Search(adc.RootEntry, filter, propertiesToLoad, searchScope.Convert());
                int total = src.Count;
                int startNum = Math.Max(pagination.pageNum - 1, 0) * pagination.pageSize;

                var data = src.OfType<SearchResult>().Select(n =>
                {
                    return n.Properties?.ConvertTo<Person>();

                }).ToList();

                return data;

            }
        }



        /// <summary>
        /// 创建人员
        /// </summary>
        /// <param name="orgCn">所处组织CN</param>
        /// <param name="person">人员信息</param>
        /// <param name="password">密码</param>
        /// <returns>成功True，失败False</returns>
        public bool Create(string orgCn, Person person, string password)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                DirectoryEntry org = null;
                var orgDe = new OrganizationAccess().Single(adc.RootEntry, orgCn);
                if (orgDe == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"组织【CN:{orgCn}】不存在，创建人员请求无法继续。");
                }

                org = orgDe.GetDirectoryEntry();
                var result = new PersonAccess().Create(org, person, password);
                return result;
            }
        }

        /// <summary>
        /// 修改人员
        /// </summary>
        /// <param name="person">
        /// 修改的人员信息
        /// 唯一标识：SamAccountName
        /// </param>
        /// <returns>成功True，失败False</returns>
        public bool Update(Person person)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var access = new PersonAccess();
                var personDes = access.Single(adc.RootEntry, person.SamAccountName);
                if (personDes == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"人员【{person.SamAccountName}】不存在，修改人员请求无法继续。");
                }

                return access.Update(personDes.GetDirectoryEntry(), person);
            }
        }

        /// <summary>
        /// 移动人员
        /// </summary>
        /// <param name="sAMAccountName">人员账户名</param>
        /// <param name="orgCn">目标组织CN</param>
        /// <returns>成功True，失败False</returns>
        public bool Move(string sAMAccountName, string orgCn)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                DirectoryEntry org = null;
                var orgDe = new OrganizationAccess().Single(adc.RootEntry, orgCn);
                if (orgDe == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"组织【CN:{orgCn}】不存在，移动人员请求无法继续。");
                }

                org = orgDe.GetDirectoryEntry();
                var access = new PersonAccess();
                var personDes = access.Single(adc.RootEntry, sAMAccountName);

                if (personDes == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"人员【{sAMAccountName}】不存在，移动人员请求无法继续。");
                }

                return access.Move(org, personDes?.GetDirectoryEntry());
            }
        }

        /// <summary>
        /// 删除人员
        /// </summary>
        /// <param name="sAMAccountName">账户名</param>
        /// <returns>成功True，失败False</returns>
        public bool Delete(string sAMAccountName)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var access = new PersonAccess();
                var personDes = access.Single(adc.RootEntry, sAMAccountName);
                if (personDes == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"人员【{sAMAccountName}】不存在，删除请求无法继续。");
                }
                return access.Delete(personDes?.GetDirectoryEntry());
            }
        }

        /// <summary>
        /// 重置密码
        /// </summary>
        /// <param name="sAMAccountName">账户名</param>
        /// <param name="isForce">
        /// 是否强制修改
        /// 强制修改不校验原始密码
        /// </param>
        /// <param name="oldPassword">
        /// 原始密码
        /// </param>
        /// <param name="newPassword">
        /// 新密码
        /// </param>
        /// <returns>成功True，失败False</returns>
        public bool ResetPassword(string sAMAccountName, bool isForce, string oldPassword, string newPassword)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var access = new PersonAccess();
                var personDes = access.Single(adc.RootEntry, sAMAccountName);
                if (personDes == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"人员【{sAMAccountName}】不存在，无法继续重置密码。");
                }
                if (!isForce && !CheckPassword(sAMAccountName, oldPassword))
                {
                    throw new UnauthorizedAccessException("原密码错误，无法继续重置密码。");
                }
                return access.ResetPassword(personDes.GetDirectoryEntry(), newPassword);
            }
        }

        /// <summary>
        /// 校验密码
        /// </summary>
        /// <param name="sAMAccountName">账户名</param>
        /// <param name="password">密码</param>
        /// <returns>成功True，失败False</returns>
        public bool CheckPassword(string sAMAccountName, string password)
        {
            ADCInfo.UserName = sAMAccountName;
            ADCInfo.Password = password;
            try
            {
                using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
                {
                    if (adc == null || adc.RootEntry == null)
                    {
                        return false;
                    }
                    return true;
                }
            }
            catch (Exception ex)
            {
                throw new UnauthorizedAccessException("原密码错误。", ex);
            }
        }

        /// <summary>
        /// 是否启用账户
        /// </summary>
        /// <param name="sAMAccountName">账户名</param>
        /// <param name="enable">是否启用</param>
        /// <returns>成功True，失败False</returns>
        public bool Enable(string sAMAccountName, bool enable)
        {
            using (var adc = new ADConnection(ADCInfo.LDAPPath, ADCInfo.UserName, ADCInfo.Password))
            {
                var access = new PersonAccess();
                var personDes = access.Single(adc.RootEntry, sAMAccountName);
                if (personDes == null)
                {
                    throw new ActiveDirectoryObjectNotFoundException($"人员【{sAMAccountName}】不存在，请求无法继续。");
                }
                return access.Enable(personDes.GetDirectoryEntry(), enable);
            }
        }
    }
}
